﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Xceed.Silverlight.Data
{
  internal class SyncDataSourceEnumerator : AsyncToSyncEnumerator<DataPath>, ISyncDataSourceEnumerator
  {
    internal SyncDataSourceEnumerator( DataSourceEnumeratorBase asyncEnumerator )
      : base( asyncEnumerator )
    {
    }

    public long Index
    {
      get
      {
        return this.AsyncEnumerator.Index;
      }
    }

    public long ItemCount
    {
      get
      {
        return this.AsyncEnumerator.ItemCount;
      }
    }

    private DataSourceEnumeratorBase AsyncEnumerator
    {
      get
      {
        return ( DataSourceEnumeratorBase )this.ChildEnumerator;
      }
    }

    public event EventHandler<IndexChangedEventArgs> IndexChanged
    {
      add
      {
        this.AsyncEnumerator.IndexChanged += value;
      }
      remove
      {
        this.AsyncEnumerator.IndexChanged -= value;
      }
    }

    public event EventHandler ItemCountChanged
    {
      add
      {
        this.AsyncEnumerator.ItemCountChanged += value;
      }
      remove
      {
        this.AsyncEnumerator.ItemCountChanged -= value;
      }
    }

    public bool MoveAndFetch(
      bool approximateMove,
      long expectedMoveCount,
      int expectedFetchCount,
      out Nullable<long> actualMoveCount,
      out ICollection<DataPath> fetchedItems,
      out RelativeOffset endPositionOffset,
      out EstimateInt64 totalCount )
    {
      return this.AsyncEnumerator.SyncMoveAndFetch(
               approximateMove,
               expectedMoveCount,
               expectedFetchCount,
               out actualMoveCount,
               out fetchedItems,
               out endPositionOffset,
               out totalCount );
    }

    public GroupFetchResult FetchGroup( DataPath groupPath, GroupTarget groupTarget, int expectedFetchCount )
    {
      return this.AsyncEnumerator.SyncFetchGroup( groupPath, groupTarget, expectedFetchCount );
    }

    public void Reset()
    {
      IAsyncResult asyncResult = this.AsyncEnumerator.BeginReset( null, null );
      this.AsyncEnumerator.EndReset( asyncResult );
    }

    public bool IsFirst( DataPath path, int levelDepth )
    {
      return this.AsyncEnumerator.IsFirst( path, levelDepth );
    }

    #region IPendingRequests Members

    public bool HasPendingRequests
    {
      get
      {
        return this.AsyncEnumerator.HasPendingRequests;
      }
    }

    public event EventHandler HasPendingRequestsChanged
    {
      add
      {
        this.AsyncEnumerator.HasPendingRequestsChanged += value;
      }
      remove
      {
        this.AsyncEnumerator.HasPendingRequestsChanged -= value;
      }
    }

    #endregion //IPendingRequests Members

    #region IDisposable Members

    private bool m_disposed; //false

    protected override void Dispose( bool disposing )
    {
      if( !m_disposed )
      {
        try
        {
          if( disposing )
          {
            this.AsyncEnumerator.Dispose();
          }

          m_disposed = true;
        }
        finally
        {
          base.Dispose( disposing );
        }
      }
    }

    #endregion IDisposable Members

    #region IEnumerator<DataPath> Members

    public DataPath Current
    {
      get
      {
        Nullable<long> actualMove;
        ICollection<DataPath> fetchedItems;
        RelativeOffset endPositionOffset;
        EstimateInt64 totalCount;

        bool ret = this.MoveAndFetch(
                     false,
                     0,
                     1,
                     out actualMove,
                     out fetchedItems,
                     out endPositionOffset,
                     out totalCount );

        if( !ret )
          throw new InvalidOperationException( "Current is before first or after last." );

        return fetchedItems.First();
      }
    }

    #endregion IEnumerator<DataPath> Members

    #region IEnumerator Members

    object IEnumerator.Current
    {
      get
      {
        return this.Current;
      }
    }

    public bool MoveNext()
    {
      Nullable<long> actualMoveCount;
      ICollection<DataPath> fetchedItems;
      RelativeOffset endPositionOffset;
      EstimateInt64 totalCount;

      return this.MoveAndFetch(
               false,
               1,
               0,
               out actualMoveCount,
               out fetchedItems,
               out endPositionOffset,
               out totalCount );
    }

    #endregion IEnumerator Members
  }
}
